/*
 * 
 */

package org.gpp.proj1.robot.action.parser;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;

import org.gpp.proj1.robot.action.step.ActionStep;
import org.gpp.proj1.robot.action.step.ChangeAnimationActionStep;
import org.gpp.proj1.robot.action.step.ChangeTargetAnimationActionStep;
import org.gpp.proj1.robot.action.step.DelayActionStep;
import org.gpp.proj1.robot.action.step.EmissionActionStep;
import org.gpp.proj1.robot.action.step.SetAttackAnimationActionStep;
import org.gpp.proj1.robot.action.step.StopEmissionActionStep;

/**
 * 
 * @author Gustavo de Farias
 */
public class ActionFileParser {
	
	// valid commands
	private static final String SET_ROBOT_ANIMATION = "setRobotAnimation";
	private static final String WAIT = "wait";
	private static final String EMIT_PARTICLE = "emitParticle";
	private static final String STOP_EMIT_PARTICLE = "stopParticleEmission";
	private static final Object SET_ATTACK_ANIMATION = "setAttackAnimation";
	private static final Object SET_TARGET_ANIMATION = "setTargetAnimation";
	
	/**
	 * @param fileName
	 * @return
	 * @throws MalformedActionScriptException
	 * @throws IOException
	 */
	public static List<ActionStep> parseFile( String fileName ) throws MalformedActionScriptException, IOException {
		
		BufferedReader reader = new BufferedReader(new FileReader(fileName));
		String line;

		// BEGIN
		while ((line = reader.readLine()) != null && !line.trim().equals("begin")) {
			if (!ignoreLine(line)) {
				reader.close();
				throw new MalformedActionScriptException("No commands expected before 'begin' clause.");
			}
		}

		if (line == null) {
			reader.close();
			throw new MalformedActionScriptException("'begin' clause missing.");
		}

		// The empty commands (steps) list
		List<ActionStep> stepList = new LinkedList<ActionStep>();
		
		// COMMANDS
		// END
		while ((line = reader.readLine()) != null && !line.trim().equals("end")) {
			if (!ignoreLine(line)) {
				
				line = line.trim();
				
				String command; // command
				String[] params; // parameters for each command
				try {
					command = line.substring(0, line.indexOf("(")).trim();
					params = line.substring(line.indexOf("(") + 1, line.lastIndexOf(")")).trim().split("[\\s,]+");
				} catch (RuntimeException e) {
					reader.close();
					throw new MalformedActionScriptException("Syntax error in command call. Try: command(param1, param2) or command()");
				}
				
				// test for a specific command
				if (command.equals(SET_ROBOT_ANIMATION)) {
					
					if (params.length < 1) {
						reader.close();
						throw new MalformedActionScriptException("1 parameter expected.");
					}

					stepList.add(new ChangeAnimationActionStep( params[0]));
				}
				else if (command.equals(WAIT)) {
					
					if (params.length < 1) {
						reader.close();
						throw new MalformedActionScriptException("1 parameter expected.");
					}
					
					try {
						stepList.add(new DelayActionStep(Long.parseLong(params[0])));
					} catch (NumberFormatException e) {
						reader.close();
						throw new MalformedActionScriptException("Long parameter expected.");
					}
				}
				else if (command.equals(EMIT_PARTICLE)) {
					
					if (params.length < 2) {
						reader.close();
						throw new MalformedActionScriptException("2 parameters expected.");
					}
					
					stepList.add(new EmissionActionStep( params[0], params[1] ));
				} else if (command.equals(STOP_EMIT_PARTICLE)) {
					
					if (params.length < 1) {
						reader.close();
						throw new MalformedActionScriptException("2 parameters expected.");
					}
					
					stepList.add(new StopEmissionActionStep( params[0] ));
				} else if (command.equals(SET_ATTACK_ANIMATION)) {
					
					stepList.add( new SetAttackAnimationActionStep( params[0] ) );
				} else if (command.equals(SET_TARGET_ANIMATION)) {
					
					stepList.add( new ChangeTargetAnimationActionStep( params[0] ) );
				}
				// invalid command
				else {
					reader.close();
					throw new MalformedActionScriptException("Unknow command in line: " + line);
				}
			}
		}

		if (line == null) {
			reader.close();
			throw new MalformedActionScriptException("'end' clause missing.");
		}
		else {
			while ((line = reader.readLine()) != null) {
				if (!ignoreLine(line)) {
					reader.close();
					throw new MalformedActionScriptException("No steps expected after 'end' clause.");
				}
			}
		}
		
		reader.close();

		// Returns the action executor (commands collection)
		return stepList;
	}
	
	/**
	 * @param line
	 * @return
	 */
	private static boolean ignoreLine(String line) {
		
		// comments and blank lines are ignored
		return line.trim().equals("") || line.trim().startsWith("#");
	}
}